#pragma once

#include <ctime>

#include "../error_codes.h"
#include "net_common.h"
#include "network_message/network_message.h"
#include "network_message/network_message_handler.h"
#include "network_message/protobuf/heart_beat.pb.h"
#include <QDebug>

#define NET_HEART_BEAT_INTERVAL 1  /* 心跳发包间隔时间，单位：s */

class tcp_client :
    public std::enable_shared_from_this<tcp_client>,
    private boost::noncopyable {
public:
    tcp_client(boost::asio::io_context &io_context) :
        socket_(io_context),
        heart_beat_timer_(io_context)
    {

    }

    int start(const tcp::endpoint &endpoint)
    {
        auto self = shared_from_this();
        socket_.async_connect(endpoint, [this, self](boost::system::error_code ec) {
            if (ec) {
                return;
            }
            std::cout << "connected to server." << std::endl;
            connected_ = true;

            do_read();
            // init_heart_beat_timer();
        });

        return EC_OK;
    }

    int send_message(const std::string &msg);

    int heart_beat()
    {
        HeartBeatC2SProto heart_beat;
        heart_beat.set_sequence(1);
        auto time_stamp = time(nullptr);
        heart_beat.set_timestamp(time_stamp);

        auto msg_data_str = heart_beat.SerializeAsString();

        network_message msg(MSG_TYPE_C2S_HEARTBEAT, msg_data_str);
        send_message(msg.to_string());

        return EC_OK;
    }

    void do_read()
    {
        read_header();
    }

    bool is_connected() const
    {
        return connected_;
    }

    void stop()
    {
        boost::system::error_code ec;
        ec = socket_.shutdown(tcp::socket::shutdown_both, ec);
        ec = socket_.close(ec);
        heart_beat_timer_.cancel();
        connected_ = false;
    }
private:
    void on_read_header_complete(boost::system::error_code ec, std::size_t length);
    int read_header();
    void on_read_body_complete(boost::system::error_code ec, std::size_t length);
    int read_body(std::size_t size_to_read);
    int current_body_size() const 
    {
        return cur_msg_header_.msg_size_;
    }

    int init_heart_beat_timer()
    {
        heart_beat_timer_.expires_after(std::chrono::seconds(NET_HEART_BEAT_INTERVAL));
        auto self = shared_from_this();
        heart_beat_timer_.async_wait([this, self](boost::system::error_code ec) {
            if (ec) {
                return;
            }

            heart_beat();   /* 发送心跳包 */
            // init_heart_beat_timer();
        });

        return EC_OK;
    }

    bool connected_ = false;
    uint32_t heaer_beat_seq_ = 0;   /* 心跳保活机制序列号 */
    std::size_t readed_header_size_ = 0;
    std::size_t readed_body_size_ = 0;
    message_header cur_msg_header_ = { 0 };
    char msg_header_buf_[NET_MESSAGE_HEADER_SIZE] = { 0 };  /* msg_header_buf_用来缓存读取的消息头，\
        当读取到一个完整的消息头时，将消息头拷贝到cur_msg_header_中，msg_header_buf_继续用于读取下一条消息头 */
    char msg_body_buf_[NET_MESSAGE_BODY_MAX_SIZE] = { 0 };
    tcp::socket socket_;

    net::steady_timer heart_beat_timer_;
};
